﻿using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using static Unity.Burst.Intrinsics.X86.Avx;

/// <summary>
/// 屏幕空间渲染通道
/// </summary>
public class ScreenSpacePlaneReflectionPass : ScriptableRenderPass
{

    /// <summary>
    /// 基于GPU高性运算，屏幕反射Shader
    /// </summary>
    public ComputeShader SSPRCS;

    /// <summary>
    /// 屏幕反射设置功能
    /// </summary>
    private SSRPFeature.Setting setting;

    /// <summary>
    /// 纹理水平大小
    /// </summary>
    private int XSize;

    /// <summary>
    /// 纹理垂直大小
    /// </summary>
    private int YSize;

    /// <summary>
    ///高性能计算线程对象 
    /// </summary>
    private SSRPFeature.Thread SSRPthreadInfo = new SSRPFeature.Thread();

    /// <summary>
    /// 颜色缓冲区
    /// 定义一张RT用来存储反射图像
    /// </summary>
    private static readonly int reflectColorId = Shader.PropertyToID("_ReflectColorRT");

    /// <summary>
    /// 深度缓存区
    /// 定义一张RT用来存储反射图像的深度贴图
    /// </summary>
    private static readonly int reflectDepthBufferId = Shader.PropertyToID("_ReflectDepthBufferRT");

    /// <summary>
    /// 平面高度
    /// </summary>
    private static readonly int reflectPlaneHeightId = Shader.PropertyToID("_ReflectPlaneHeight");

    /// <summary>
    /// 纹理大小
    /// </summary>
    private static readonly int rtSizeId = Shader.PropertyToID("_RTSize");

    /// <summary>
    /// 边缘淡隐淡出
    /// </summary>
    private static readonly int fadeOutToEdgeId = Shader.PropertyToID("_FadeOut2Edge");

    /// <summary>
    /// 反射纹理大小
    /// </summary>
    private static readonly int reflectRTId = Shader.PropertyToID("_ReflectRT");

    /// <summary>
    /// 屏幕颜色纹理
    /// </summary>
    private static readonly int screenColorTexId = Shader.PropertyToID("_ScreenColorTex");

    /// <summary>
    /// 屏幕深度纹理
    /// </summary>
    private static readonly int screenDepthTexId = Shader.PropertyToID("_ScreenDepthTex");

    private static readonly int IVPMatrixId = Shader.PropertyToID("_IVPMatrix");

    private static readonly int VPMatrixId = Shader.PropertyToID("_VPMatrix");


    private static int frustumCornersId = Shader.PropertyToID("_FrustumCornersRay");

    /// <summary>
    /// 反射颜色图对象
    /// </summary>
    private RenderTargetIdentifier reflectColorID = new RenderTargetIdentifier(reflectColorId);

    /// <summary>
    /// 反射深度图对象
    /// </summary>
    private RenderTargetIdentifier reflectDepthBufferID = new RenderTargetIdentifier(reflectDepthBufferId);

    /// <summary>
    /// 相机颜色值纹理
    /// </summary>
    //private RenderTargetIdentifier cameraColorTextureID = new RenderTargetIdentifier("_CameraColorTexture");

    /// <summary>
    /// 相机深度纹理
    /// </summary>
    //private RenderTargetIdentifier cameraDepthTextureID = new RenderTargetIdentifier("_CameraDepthTexture");

    public ScreenSpacePlaneReflectionPass(SSRPFeature.Setting setting, ComputeShader sSPRShader)
    {
        this.setting = setting;
        this.SSPRCS = sSPRShader;
    }

    /// <summary>
    /// 配置相关属性
    /// </summary>
    /// <param name="cmd"></param>
    /// <param name="cameraTextureDescriptor"></param>
    public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
    {
        base.Configure(cmd, cameraTextureDescriptor);
    }


    private void InitTexture(CommandBuffer cmd)
    {
        //计算屏幕宽、高比
        float aspect = (float)Screen.height / Screen.width;
        //水平分量数量
        this.SSRPthreadInfo.GroupThreadX = 8;
        ////垂直分量数量
        this.SSRPthreadInfo.GroupThreadY = 8;
        ////具体在Y方向，相隔分辨率数值
        this.SSRPthreadInfo.GroupY = this.setting.RTSize / SSRPthreadInfo.GroupThreadX;
        //具体在X方向，相隔分辨率数值
        this.SSRPthreadInfo.GroupX = Mathf.RoundToInt(this.SSRPthreadInfo.GroupY / aspect);
        //计算水平方向纹理大小
        this.XSize = this.SSRPthreadInfo.GroupThreadX * this.SSRPthreadInfo.GroupX;
        //计算垂直方向纹理大小
        this.YSize = this.SSRPthreadInfo.GroupThreadY * this.SSRPthreadInfo.GroupY;
        //实例化申请纹理大小
        //R 8 G 8 B 8 A 8
        RenderTextureDescriptor desc = new RenderTextureDescriptor(XSize, YSize, RenderTextureFormat.ARGB32);
        //绑定UAV（允许无序访问），运行Shader并行处理纹理
        desc.enableRandomWrite = true;
        cmd.GetTemporaryRT(reflectColorId, desc);
        if (this.setting.HDR)
        {
            //HDR
            desc.colorFormat = RenderTextureFormat.ARGBHalf;
        }
        else
        {
            //设定颜色格式只需要R通道，并且精度要求不高8字节即可
            desc.colorFormat = RenderTextureFormat.ARGB32;
        }
        desc.colorFormat = RenderTextureFormat.RFloat;
        //申请反射深度贴图空间
        cmd.GetTemporaryRT(reflectDepthBufferId, desc);
        //加载ComputerShader对象
        if (this.SSPRCS == null)
        {
            Debug.LogError("Screen Space Plane Reflect Computer Shader is null!");
        }
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        if (this.SSPRCS == null)
        {
            Debug.LogError("SSRP ComputerShader丢失!");
            return;
        }
        if (renderingData.cameraData.camera != Camera.main)
        {
            return;
        }

        if (this.setting.On)
        {
            CommandBuffer cmd = CommandBufferPool.Get(this.setting.CmdName);
            InitTexture(cmd);
            cmd.SetComputeVectorParam(this.SSPRCS, rtSizeId, new Vector2(this.XSize, this.YSize));
            cmd.SetComputeFloatParam(this.SSPRCS, reflectPlaneHeightId, this.setting.ReflectHeight);
            cmd.SetComputeFloatParam(this.SSPRCS, fadeOutToEdgeId, this.setting.FadeOutRange);
            //Camera camera = renderingData.cameraData.camera;
            //Matrix4x4 mat = GL.GetGPUProjectionMatrix(camera.projectionMatrix, true);
            //Matrix4x4 VP = mat * camera.worldToCameraMatrix;
            //Matrix4x4 IVP = Matrix4x4.Inverse(VP);
            //cmd.SetComputeMatrixParam(this.SSPRCS, "_IVPMatrix", IVP);
            //cmd.SetComputeMatrixParam(this.SSPRCS, "_VPMatrix", VP);

            int kernel_MobilePathSinglePassColorRTDirectResolve = this.SSPRCS.FindKernel("ReflectTexture");
            cmd.SetComputeTextureParam(this.SSPRCS, kernel_MobilePathSinglePassColorRTDirectResolve, reflectRTId, this.reflectColorID);
            cmd.SetComputeTextureParam(this.SSPRCS, kernel_MobilePathSinglePassColorRTDirectResolve, reflectDepthBufferId, this.reflectDepthBufferID);
            //cb.SetComputeTextureParam(cs, kernel_MobilePathSinglePassColorRTDirectResolve, "_CameraOpaqueTexture", new RenderTargetIdentifier("_CameraOpaqueTexture"));
            //cb.SetComputeTextureParam(cs, kernel_MobilePathSinglePassColorRTDirectResolve, "_CameraDepthTexture", new RenderTargetIdentifier("_CameraDepthTexture"));
            cmd.DispatchCompute(this.SSPRCS, kernel_MobilePathSinglePassColorRTDirectResolve, this.SSRPthreadInfo.GroupX, this.SSRPthreadInfo.GroupY, 1);
            cmd.SetGlobalTexture(reflectRTId, this.reflectColorID);
            //cmd.Blit(this.reflectColorID, renderingData.cameraData.renderer.cameraColorTargetHandle);
            //cmd.Blit(this.reflectDepthBufferID, renderingData.cameraData.renderer.cameraColorTargetHandle);

            if (this.setting.ApplyFillHoleFix)
            {
                int kernel_FillHoles = this.SSPRCS.FindKernel("FillHoles");
                cmd.SetComputeTextureParam(this.SSPRCS, kernel_FillHoles, "ColorRT", this.reflectColorID);
                //cb.SetComputeTextureParam(cs, kernel_FillHoles, "PackedDataRT", _SSPR_PackedDataRT_rti);
                cmd.DispatchCompute(this.SSPRCS, kernel_FillHoles, this.SSRPthreadInfo.GroupX, this.SSRPthreadInfo.GroupY, 1);
            }
            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
        }
    }

    public override void FrameCleanup(CommandBuffer cmd)
    {
        base.FrameCleanup(cmd);
        cmd.ReleaseTemporaryRT(reflectColorId);
        cmd.ReleaseTemporaryRT(reflectDepthBufferId);
    }
}
